package com.onelap.bls.tc.activity.bluetooth_le;

import android.app.Activity;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;

import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ServiceUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.onelap.bls.tc.config.Constant;

import java.io.UnsupportedEncodingException;
import java.util.Timer;
import java.util.TimerTask;

import static android.content.Context.BIND_AUTO_CREATE;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.BATTERY_LEVEL_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.BATTERY_SERVICE_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.CCCD;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.DEVICE_INFO_SERVICE_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.EXTRA_DATA;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.Manufacturer_Name_String_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.RX_CHAR_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.RX_SERVICE_UUID;
import static com.onelap.bls.tc.activity.bluetooth_le.BluetoothLeParams.ServiceParams.TX_CHAR_UUID;

public class BluetoothLeUtil {

    private BluetoothLeUtil bluetoothLeUtil;

    private BluetoothUtilCallback bluetoothUtilCallback;

    private BluetoothAdapter bluetoothAdapter = null;

    private BluetoothGatt bluetoothGatt = null;

    private BluetoothLeService bluetoothService = null;
    private BluetoothGattCharacteristic bluetoothGattCharacteristicBattery;


    public BluetoothLeUtil(BluetoothUtilCallback bluetoothUtilCallback) {
        this.bluetoothLeUtil = this;
        this.bluetoothUtilCallback = bluetoothUtilCallback;
    }

    public BluetoothUtilCallback getBluetoothUtilCallback() {
        return this.bluetoothUtilCallback;
    }

    /**
     * 打开蓝牙
     */
    public void openBluetooth() {
        Activity topActivity = ActivityUtils.getTopActivity();
        if (topActivity == null)
            return;
        Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        topActivity.startActivityForResult(enableIntent, Constant.REQUEST_INTENT_ENABLE_BLUETOOTH);
    }


    /**
     * 获取BluetoothAdapter
     *
     * @param context context
     * @return BluetoothAdapter
     */
    public BluetoothAdapter getBluetoothAdapter(Context context) {
        BluetoothAdapter bluetoothAdapter;
        BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager != null ? bluetoothManager.getAdapter() : null;
        this.bluetoothAdapter = bluetoothAdapter;
        return bluetoothAdapter;
    }


    /**
     * 搜索设备
     *
     * @param bluetoothAdapter bluetoothAdapter
     * @param search           是否搜索
     */
    public void searchBluetoothDevice(final BluetoothAdapter bluetoothAdapter, Boolean search) {
        if (bluetoothAdapter == null) {
            LogUtils.i("SearchBluetoothDevice", "SearchBluetoothDevice：BluetoothAdapter == NULL");
            return;
        }
        if (search) {
            bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_ServiceConnection_Start, null, null, 0, null, null, null);
            bluetoothAdapter.startLeScan(leScanCallback);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    bluetoothLeUtil.searchBluetoothDevice(bluetoothAdapter, false);
                }
            }, BluetoothLeParams.Params.SEARCH_TIME);
        } else {
            bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_ServiceConnection_Stop, null, null, 0, null, null, null);
            bluetoothAdapter.stopLeScan(leScanCallback);
        }
    }

    /**
     * 绑定蓝牙服务
     *
     * @param service 蓝牙服务
     */
    public void bindBluetoothService(Context context, Class<? extends Service> service, String... intentActions) {
        IntentFilter intentFilter = new IntentFilter();
        for (String s : intentActions) {
            intentFilter.addAction(s);
        }
        ServiceUtils.bindService(service, serviceConnection, BIND_AUTO_CREATE);
        LocalBroadcastManager.getInstance(context).registerReceiver(broadcastReceiver, intentFilter);
    }

    /**
     * 解绑蓝牙服务
     */
    public void unBindBluetoothService(Context context) {
        ServiceUtils.unbindService(serviceConnection);
        LocalBroadcastManager.getInstance(context).unregisterReceiver(broadcastReceiver);
    }

    /**
     * 开启蓝牙连设备
     *
     * @param bluetoothLeService bluetoothLeService
     * @param bluetoothDevice    bluetoothDevice
     */
    public void openBleConnectDevice(BluetoothLeService bluetoothLeService, BluetoothDevice bluetoothDevice) {
        this.bluetoothService = bluetoothLeService;
        //closeBleConnectDevice();
        if (bluetoothAdapter == null) {
            ToastUtils.showShort("ConnectDevice：BluetoothAdapter == NULL");
            return;
        }
        if (bluetoothDevice.getAddress() == null) {
            ToastUtils.showShort("ConnectDevice：BluetoothDeviceAddress == NULL");
            return;
        }
        bluetoothGatt = bluetoothDevice.connectGatt(bluetoothLeService, false, bluetoothGattCallback);
    }

    /**
     * 关闭蓝牙连设备
     */
    public void closeBleConnectDevice() {
        if (bluetoothGatt != null) {
            bluetoothGatt.close();
            bluetoothGatt = null;
        }
    }


    public void writeRXCharacteristicUTF_8(String tempValue) throws UnsupportedEncodingException {
        if (bluetoothGatt == null) {
            ToastUtils.showShort("设备未连接");
            return;
        }
        BluetoothGattService tempService = bluetoothGatt.getService(RX_SERVICE_UUID);
        if (tempService == null) {
            ToastUtils.showShort("UUID Service == NULL");
            return;
        }
        BluetoothGattCharacteristic tempChar = tempService.getCharacteristic(RX_CHAR_UUID);
        if (tempChar == null) {
            ToastUtils.showShort("Rx charateristic not found!");
            return;
        }
        tempChar.setValue(tempValue.getBytes("UTF-8"));
        boolean status = bluetoothGatt.writeCharacteristic(tempChar);
        LogUtils.i("writeRXCharacteristicUTF_8", "write TXchar - status=" + status);
    }

    /**
     * 搜索设备回调
     */
    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_LeScanCallback_Device_Find, null, bluetoothDevice, i, bytes, null, null);
        }
    };

    /**
     * 服务连接回调
     */
    private ServiceConnection serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder rawBinder) {
            bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_ServiceConnection_ServiceConnected, null, null, 0, null, rawBinder, null);
        }

        public void onServiceDisconnected(ComponentName classname) {
            bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_ServiceConnection_ServiceDisconnected, null, null, 0, null, null, null);
        }
    };


    /**
     * Enable Notification on TX characteristic
     *
     * @return
     */
    public void setCharacteristicNotification(boolean enabled) {

        if (bluetoothAdapter == null || bluetoothGatt == null) {
            LogUtils.i("", "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGattService RxService = bluetoothGatt.getService(RX_SERVICE_UUID);
        if (RxService == null) {
            ToastUtils.showShort("UUID Service == NULL");
            return;
        }
        BluetoothGattCharacteristic TxChar = RxService.getCharacteristic(TX_CHAR_UUID);
        if (TxChar == null) {
            ToastUtils.showShort("Rx charateristic not found!");
            return;
        }
        bluetoothGatt.setCharacteristicNotification(TxChar, enabled);

        BluetoothGattDescriptor descriptor = TxChar.getDescriptor(CCCD);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        bluetoothGatt.writeDescriptor(descriptor);
    }

    public void setCharacteristicNotificationBattery(boolean enabled) {

        if (bluetoothAdapter == null || bluetoothGatt == null) {
            LogUtils.i("", "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGattService RxService = bluetoothGatt.getService(BATTERY_SERVICE_UUID);
        if (RxService == null) {
            ToastUtils.showShort("Battery UUID Service == NULL");
            return;
        }
        BluetoothGattCharacteristic TxChar = RxService.getCharacteristic(BATTERY_LEVEL_UUID);
        if (TxChar == null) {
            ToastUtils.showShort("Battery Rx charateristic not found!");
            return;
        }
        bluetoothGatt.setCharacteristicNotification(TxChar, enabled);

        /*BluetoothGattDescriptor descriptor = TxChar.getDescriptor(CCCD);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);*/
        /*bluetoothGatt.writeDescriptor(descriptor);*/
        /*List<BluetoothGattDescriptor> descriptors = TxChar.getDescriptors();
        for (BluetoothGattDescriptor dp : descriptors) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(dp);
        }*/
        bluetoothGatt.readCharacteristic(TxChar);
    }

    public void setCharacteristicNotificationVersion(boolean enabled) {

        if (bluetoothAdapter == null || bluetoothGatt == null) {
            LogUtils.i("", "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGattService RxService = bluetoothGatt.getService(DEVICE_INFO_SERVICE_UUID);
        if (RxService == null) {
            ToastUtils.showShort("Battery UUID Service == NULL");
            return;
        }
        BluetoothGattCharacteristic TxChar = RxService.getCharacteristic(Manufacturer_Name_String_UUID);
        if (TxChar == null) {
            ToastUtils.showShort("Battery Rx charateristic not found!");
            return;
        }
        bluetoothGatt.setCharacteristicNotification(TxChar, enabled);

       /* BluetoothGattDescriptor descriptor = TxChar.getDescriptor(CCCD);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);*/
        /*bluetoothGatt.writeDescriptor(descriptor);*/
        /*List<BluetoothGattDescriptor> descriptors = TxChar.getDescriptors();
        for (BluetoothGattDescriptor dp : descriptors) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(dp);
        }*/
        bluetoothGatt.readCharacteristic(TxChar);
        LogUtils.i("5555555555555555");
    }

    private Handler mHandler = new Handler();

    private final static int STATE_DISCONNECTED = 0;
    private final static int STATE_CONNECTING = 1;
    private final static int STATE_CONNECTED = 2;

    private final static int RUN_PERIOD = 3000;
    private final static int COUNT_PERIOD = 3000;


    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        }
    };


    private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyUpdate(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyRead(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            LogUtils.i("ConnectionStateChange", "BluetoothGatt_Status：".concat(String.valueOf(status) + "--------" + newState));
            if (status == BluetoothGatt.GATT_SUCCESS)
                switch (newState) {
                    case BluetoothProfile.STATE_CONNECTING:
                        bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Connecting, gatt, null, 0, null, null, null);
                        break;
                    case BluetoothProfile.STATE_CONNECTED:
                        bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Connected, gatt, null, 0, null, null, null);
                        try {
                            Thread.sleep(500);
                            bluetoothGatt.discoverServices();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        break;
                    case BluetoothProfile.STATE_DISCONNECTING:
                        bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_DisConnecting, gatt, null, 0, null, null, null);
                        break;
                    case BluetoothProfile.STATE_DISCONNECTED:
                        bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_DisConnected, gatt, null, 0, null, null, null);
                        break;
                }
            else {
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Connect_Fail, gatt, null, 0, null, null, null);

            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            setCharacteristicNotification(true);
            try {
                displayVersionBattery();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (status == BluetoothGatt.GATT_SUCCESS) {
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Discovered, gatt, null, 0, null, null, null);
            } else {
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Discovered_Fail, gatt, null, 0, null, null, null);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Intent intent = new Intent();
                if (TX_CHAR_UUID.equals(characteristic.getUuid())) {
                    intent.putExtra(EXTRA_DATA, characteristic.getValue());
                    bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_Data, gatt, null, 0, null, null, intent);
                } else if ((BATTERY_LEVEL_UUID.toString()).equalsIgnoreCase(characteristic.getUuid().toString())) {
                    intent.putExtra(EXTRA_DATA, characteristic.getValue());
                    bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_BatteryData, gatt, null, 0, null, null, intent);
                } else if ((Manufacturer_Name_String_UUID.toString()).equalsIgnoreCase(characteristic.getUuid().toString())) {
                    intent.putExtra(EXTRA_DATA, characteristic.getValue());
                    bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_VersionData, gatt, null, 0, null, null, intent);
                }
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Intent intent = new Intent();
            if ((Manufacturer_Name_String_UUID.toString()).equalsIgnoreCase(characteristic.getUuid().toString())) {
                intent.putExtra(EXTRA_DATA, characteristic.getValue());
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_VersionData, gatt, null, 0, null, null, intent);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Intent intent = new Intent();
            if (TX_CHAR_UUID.equals(characteristic.getUuid())) {
                intent.putExtra(EXTRA_DATA, characteristic.getValue());
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_Data, gatt, null, 0, null, null, intent);
            }
            if ((Manufacturer_Name_String_UUID.toString()).equalsIgnoreCase(characteristic.getUuid().toString())) {
                intent.putExtra(EXTRA_DATA, characteristic.getValue());
                bluetoothUtilCallback.onBluetoothUtilCallback(BluetoothLeParams.UtilCallbackStatue.STATUS_BluetoothDevice_Get_VersionData, gatt, null, 0, null, null, intent);
            }
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    };


    private void showVersion() {
        BluetoothGattService service = bluetoothGatt.getService(DEVICE_INFO_SERVICE_UUID);
        if (service == null) return;
        bluetoothGatt.readCharacteristic(service.getCharacteristic(Manufacturer_Name_String_UUID));
    }

    private void showBattery() {
        BluetoothGattService service = bluetoothGatt.getService(BATTERY_SERVICE_UUID);
        if (service == null) return;
        bluetoothGatt.readCharacteristic(service.getCharacteristic(BATTERY_LEVEL_UUID));
    }


    /**
     * 显示版本号和电量
     */
    public void displayVersionBattery() {

        if (bluetoothGatt == null)
            return;
        showBattery();
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    showVersion();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 500);
    }

    /**
     * BLeUtil工具类统一回调接口
     */
    public interface BluetoothUtilCallback {
        void onBluetoothUtilCallback(String utilCallbackStatue, BluetoothGatt gatt, BluetoothDevice device, int rssi, byte[] scanRecord, IBinder rawBinder, Intent intent);
    }
}
